How the Uptime Kuma Push Monitor Type Works for External Check-Ins

The Uptime Kuma push monitor type enables external services to report their own health status via HTTP GET requests to a unique token-protected endpoint, creating passive monitoring without polling while supporting custom status messages and latency metrics.

The push monitor type in Uptime Kuma provides a passive monitoring mechanism that inverts the traditional polling model. Instead of Uptime Kuma actively probing your services, your services push health data to the monitoring instance using a secure URL. This architecture, implemented in the louislam/uptime-kuma repository, is ideal for services behind firewalls, ephemeral CI/CD jobs, or environments where inbound access is restricted.

Architecture of the Push Monitor System

Token Generation and URL Structure

When you create a monitor with type: "push", the backend generates a cryptographically random 32-character push token stored in the pushToken field of the monitor table. This occurs in server/model/monitor.js where the model defines the pushToken property.

The frontend constructs the check-in URL through computed properties in two Vue components:

The resulting URL follows this pattern:

<base-url>/api/push/<pushToken>?status=up&msg=OK&ping=123

The API Endpoint Handler

All push requests route to router.all("/api/push/:pushToken") in server/routers/api-router.js (lines 47-146). This Express router handler validates tokens, parses query parameters, and orchestrates the heartbeat creation pipeline without requiring authentication headers, relying solely on the entropy of the push token for security.

Step-by-Step Processing Flow for External Check-Ins

When an external service performs a GET request to the push URL, Uptime Kuma executes an eight-step validation and recording process:

1. Token Validation

The router queries the database using R.findOne("monitor", " push_token = ? AND active = 1 ", [pushToken]). If the token does not match an active monitor, the request fails immediately with HTTP 404.

2. Parameter Parsing

The system extracts three query parameters from the request:

  • status: Accepts "up" (default) or "down", mapping to internal UP and DOWN constants
  • msg: Optional free-form message string (defaults to "OK")
  • ping: Optional response time in milliseconds, strictly validated to be between 0 and 100000000000 ms

3. Heartbeat Bean Creation

A new heartbeat record is instantiated via the bean pattern, populated with the monitor ID, current timestamp, parsed ping value, custom message, and the previous heartbeat's downCount. If prior heartbeats exist in the database, the system calculates the duration field representing the time elapsed since the last check-in.

4. Status Determination

If the monitor is currently under maintenance, the status is forced to MAINTENANCE regardless of the pushed status. Otherwise, the internal determineStatus() helper evaluates the final state based on the status parameter, the monitor's previous state, and its configured retry policy.

5. Uptime Calculation

The UptimeCalculator class updates the monitor's statistical graphs and aggregate uptime percentages using the new heartbeat data before database persistence.

6. Database Persistence

The heartbeat bean's end_time is set to the current timestamp, and the complete record is saved to the database via the heartbeat table.

7. Real-Time Broadcasting

The system immediately emits the heartbeat to connected clients via WebSocket using io.to(monitor.user_id).emit("heartbeat", bean.toJSON()). Aggregate statistics are refreshed and broadcast to ensure dashboard consistency.

8. Notification and Export Logic

If the heartbeat meets the criteria defined in Monitor.isImportantForNotification(), alert notifications are dispatched immediately through configured channels. For monitors already in a down state with a resendInterval configured, the system may resend notifications after the specified number of consecutive down beats. The heartbeat is optionally pushed to a Prometheus exporter before the router returns a JSON response.

Implementing External Check-Ins

cURL Example

The simplest implementation uses a standard HTTP client to push status data:

curl "https://uptime.kuma.example/api/push/AbCdEfGhIjKlMnOpQrStUvWxYz123456?status=up&msg=Backup%20completed&ping=420"

Node.js TypeScript Implementation

For services built with Node.js, the repository provides reference implementations in extra/push-examples/typescript-fetch/index.ts:

const pushURL = "https://uptime.kuma.example/api/push/AbCdEfGhIjKlMnOpQrStUvWxYz123456?status=up&msg=OK&ping=";

const push = async () => {
    await fetch(pushURL);
};

push();
setInterval(push, 60000); // Push every 60 seconds

Similar examples exist for Python, Go, PowerShell, and Bash in the extra/push-examples/ directory.

Creating Push Monitors via API

To programmatically create a push monitor, POST to the internal API endpoint:

{
  "type": "push",
  "name": "Database Backup Job",
  "interval": 3600,
  "maxretries": 3,
  "notificationIDList": [1, 2],
  "tags": ["production", "backup"]
}

The API response includes the generated pushToken, which you must extract to construct the check-in URL for your external scripts.

Why Use Push Monitors?

  • No polling overhead – Eliminates network traffic from Uptime Kuma to your services, reducing bandwidth and compute costs.
  • Firewall and NAT traversal – Works for services without public IP addresses or inbound port access, as long as the service can reach the Uptime Kuma instance.
  • Rich telemetry – The ping and msg parameters allow reporting custom metrics like job duration, queue depth, or specific error codes alongside binary up/down status.
  • CI/CD integration – Ideal for ephemeral environments like GitHub Actions, GitLab CI, or Kubernetes CronJobs where the service exists only for the duration of the task.

Summary

  • The push monitor type uses a passive architecture where external services report health via HTTP GET requests to api/push/:pushToken.
  • A 32-character random token generated in server/model/monitor.js secures the endpoint and maps requests to specific monitors.
  • The router in server/routers/api-router.js handles validation, heartbeat creation, uptime calculation, WebSocket broadcasting, and notification triggers in a single request lifecycle.
  • Query parameters status, msg, and ping provide flexible telemetry options with built-in validation ranges.
  • Example implementations in extra/push-examples/ demonstrate integration patterns for Bash, TypeScript, Python, and other languages.

Frequently Asked Questions

What happens if I use an invalid push token?

Uptime Kuma returns an HTTP 404 response with the JSON payload { ok: false, msg: "Monitor not found or not active" }. The router queries the database for a matching active monitor using R.findOne("monitor", " push_token = ? AND active = 1 ", [pushToken]) and rejects requests where no match exists.

Can I use push monitors for services behind a corporate firewall?

Yes. The push monitor is specifically designed for this scenario. Since the communication is initiated by your service outbound to Uptime Kuma, no inbound firewall rules or NAT port forwarding are required on the monitored service's network.

How does Uptime Kuma handle maintenance windows for push monitors?

If a monitor is under maintenance mode when a push request arrives, the system forces the heartbeat status to MAINTENANCE regardless of the status parameter sent in the request. This prevents false positive notifications while scheduled work is performed.

What is the maximum valid value for the ping parameter?

The ping parameter accepts values between 0 and 100000000000 milliseconds (approximately 3.17 years). The router validates this range in server/routers/api-router.js and rejects out-of-bounds values to prevent database overflow or logic errors.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →