Bulk update all your Uptime Kuma monitors with a single script
Uptime Kuma has no bulk edit button. Clicking through dozens of monitors one by one is nobody's idea of a good time. This script updates the heartbeat interval, retries and retry interval across all your monitors in one shot.
If you are running Uptime Kuma with more than a handful of monitors, you have probably hit that wall. You want to change the heartbeat interval across the board and there is no bulk edit button in sight. Clicking through 30 monitors one by one is not a workflow, it is a punishment.
So I wrote a small Python script that does it in one shot.
What it does
The script connects to your Uptime Kuma instance via its internal Socket.IO API, pulls every monitor, and updates three values across all of them:
- Heartbeat interval → 120 seconds
- Max retries → 2
- Retry interval → 60 seconds
Monitors that are already set correctly get a clean Already up to date message and are left alone. Everything is configured through a .env file so nothing sensitive ends up hardcoded.
There is one gotcha worth mentioning: the Python wrapper used to talk to Uptime Kuma's API throws an error when a monitor has a null dns_resolve_type, which happens on non-DNS monitors. The script patches that validation silently before it runs, so you do not have to touch your monitor setup at all.
The .env file
Create a .env file in the same folder as the script:
UPTIME_KUMA_URL=http://10.10.10.10:3001
UPTIME_KUMA_USERNAME=admin
UPTIME_KUMA_PASSWORD=your_password_here
NEW_INTERVAL=120
NEW_MAX_RETRIES=2
NEW_RETRY_INTERVAL=60
Change the values to match your setup. If you leave UPTIME_KUMA_PASSWORD empty, the script will prompt you for it at runtime instead.
The script
Save this as bulk_update_kuma.py:
#!/usr/bin/env python3
# --- Patch BEFORE importing UptimeKumaApi ---
import uptime_kuma_api.api as _api
_orig_check = _api._check_arguments_monitor
def _patched_check(kwargs):
if kwargs.get("dns_resolve_type") is None:
kwargs["dns_resolve_type"] = "A"
_orig_check(kwargs)
_api._check_arguments_monitor = _patched_check
_orig_convert = _api._convert_monitor_input
def _patched_convert(data):
if data.get("dns_resolve_type") is None:
data["dns_resolve_type"] = "A"
return _orig_convert(data)
_api._convert_monitor_input = _patched_convert
# --- End patch ---
import os
from pathlib import Path
from getpass import getpass
from uptime_kuma_api import UptimeKumaApi
def load_env(filepath=".env"):
env_path = Path(filepath)
if env_path.exists():
with open(env_path) as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, _, value = line.partition("=")
os.environ.setdefault(key.strip(), value.strip())
load_env()
UPTIME_KUMA_URL = os.environ.get("UPTIME_KUMA_URL", "").strip()
USERNAME = os.environ.get("UPTIME_KUMA_USERNAME", "").strip()
PASSWORD = os.environ.get("UPTIME_KUMA_PASSWORD", "").strip()
NEW_INTERVAL = int(os.environ.get("NEW_INTERVAL", 120))
NEW_MAX_RETRIES = int(os.environ.get("NEW_MAX_RETRIES", 2))
NEW_RETRY_INTERVAL = int(os.environ.get("NEW_RETRY_INTERVAL", 60))
if not UPTIME_KUMA_URL:
UPTIME_KUMA_URL = input("Uptime Kuma URL: ").strip()
if not USERNAME:
USERNAME = input("Uptime Kuma username: ").strip()
if not PASSWORD:
PASSWORD = getpass("Uptime Kuma password: ")
def main():
updated = 0
already = 0
failed = 0
with UptimeKumaApi(UPTIME_KUMA_URL) as api:
api.login(USERNAME, PASSWORD)
monitors = api.get_monitors()
for monitor in monitors:
monitor_id = monitor["id"]
name = monitor.get("name", f"monitor-{monitor_id}")
monitor_type = monitor.get("type", "unknown")
if (
monitor.get("interval") == NEW_INTERVAL
and monitor.get("maxretries") == NEW_MAX_RETRIES
and monitor.get("retryInterval") == NEW_RETRY_INTERVAL
):
already += 1
print(f"ALREADY UP TO DATE {monitor_id:>4} {name}")
continue
try:
api.edit_monitor(
monitor_id,
interval=NEW_INTERVAL,
maxretries=NEW_MAX_RETRIES,
retryInterval=NEW_RETRY_INTERVAL,
)
updated += 1
print(f"UPDATE {monitor_id:>4} {name} type={monitor_type}")
except Exception as e:
failed += 1
print(f"ERROR {monitor_id:>4} {name} {e}")
print()
print(f"Done. Updated: {updated}, Already up to date: {already}, Failed: {failed}")
if __name__ == "__main__":
main()
How to run it
You do not need Python installed on your machine. Run it in a throwaway Docker container. It installs the dependency inside the container, runs the script, and disappears cleanly when done:
docker run --rm -it \
-v "$PWD:/work" \
-w /work \
python:3.12-slim \
sh -c "pip install uptime-kuma-api && python3 bulk_update_kuma.py"
Make sure your .env and bulk_update_kuma.py are in the same directory when you run that command. You will see a live log of every monitor being updated or skipped, and a summary at the end.
Note: Uptime Kuma's API is an unofficial internal Socket.IO interface. This script was written and tested against Uptime Kuma v1.x. If something breaks after an upgrade, the wrapper version (uptime-kuma-api on PyPI) is usually the first thing to check.